PRO tlb_event, Event

  wTarget = (WIDGET_INFO(Event.id,/NAME) eq 'TREE' ?  $
      WIDGET_INFO(Event.id, /tree_root) : Event.id)

  IF WIDGET_INFO(Event.id, /TLB_SIZE_EVENTS) EQ 1 THEN fractalResizeWindow, Event

  wWidget =  Event.top

  CASE wTarget OF

    WIDGET_INFO(wWidget, FIND_BY_UNAME='drawWidget') : BEGIN
      IF(TAG_NAMES(Event, /STRUCTURE_NAME) eq 'WIDGET_DRAW') THEN BEGIN
        IF (Event.type EQ 0) THEN BEGIN
          fractalMoveAndZoom, Event
        ENDIF

        ;; It's an "expose" Event, where the drawWidget has been uncovered
        ;; by moving it back on to the screen, for example.
        IF (Event.type EQ 4) THEN BEGIN
          fractalRedraw, Event
        ENDIF

      ENDIF
  END
  ELSE:
  ENDCASE

END


PRO tlb, GROUP_LEADER=wGroup, _EXTRA=_VWBExtra_

  Compile_Opt IDL2 ;; Force all integer variables to be LONG and not SHORT. Force [] for arrays

  Resolve_Routine, 'fractal_eventcb', /COMPILE_FULL_FILE ;; Load Event callback routines

  imageSize = [200, 200]

  tlb = WIDGET_BASE(GROUP_LEADER=wGroup, UNAME='tlb', XSIZE=imageSize[0], YSIZE=imageSize[1], TITLE='Mandelbrot fractal', MBAR=menuID, /TLB_SIZE_EVENTS)

  ;; Define a file menu with a single option of saving a jpeg and also to exit the program
  fileID = WIDGET_BUTTON(menuID, Value='File', /MENU)
  saveID = WIDGET_BUTTON(fileID, Value='Save as bmp', Accelerator='Alt+s', Event_Pro='fractalSave')
  exitID = WIDGET_BUTTON(fileID, Value='Exit',        Accelerator='Alt+x', Event_Pro='fractalExit')

  ;; Define an edit menu with a single option of choosing options
  editID      = WIDGET_BUTTON(menuID, Value='Edit', /MENU)
  specifyID   = WIDGET_BUTTON(editID, Value='Specify area', Accelerator='Alt+a', Event_Pro='fractalSpecifyArea')
  optionsID   = WIDGET_BUTTON(editID, Value='Options',      Accelerator='Alt+o', Event_Pro='fractalOptions')
  extraIterID = WIDGET_BUTTON(editID, Value='Iterate more', Accelerator='Alt+i', Event_Pro='fractalIterateMore')
  resetID     = WIDGET_BUTTON(editID, Value='Reset',        Accelerator='Alt+r', Event_Pro='fractalReset')

  ;; Define a view menu
  viewID    = WIDGET_BUTTON(menuID, Value='View', /MENU)
  redrawID  = WIDGET_BUTTON(viewID, Value='Redraw', Accelerator='Alt+d', Event_Pro='fractalRedraw')
  cyclectID = WIDGET_BUTTON(viewID, Value='Cycle colour table', Accelerator='Alt+c', Event_Pro='fractalCycleCT')

  ;; Define a help menu
  helpID         = WIDGET_BUTTON(menuID, Value='Help', /MENU)
  aboutID        = WIDGET_BUTTON(helpID, Value='About',        Event_Pro='fractalAbout')
  instructionsID = WIDGET_BUTTON(helpID, Value='Instructions', Event_Pro='fractalInstructions')

  ;; Note that EXPOSE_EVENTS has been set. This enables Event reporting when
  ;; the visibility of the draw widget changes, such as when it is moved off
  ;; the edge of the display screen and then back on again. When this occurs
  ;; the Event handler (tlb_event, at the top of this file) redraws the
  ;; fractal in the drawWidget. RETAIN has to be set to 0 for the drawWidget
  ;; to ensure that the expose events are generated.
  drawWidget = WIDGET_DRAW(tlb, UNAME='drawWidget', XSIZE=imageSize[0], YSIZE=imageSize[1], /BUTTON_EVENTS, RETAIN=0, /EXPOSE_EVENTS, GRAPHICS_LEVEL=2)

  ;; Set the default range of real and imaginary numbers and
  ;; also the maximum number of iterations.
  rMin = -2.0D
  rMax =  0.5D
  iMin = -1.25D
  iMax =  1.25D
  numIter = 50

  ;; Set the default colour table and the switch for whether
  ;; the colours should be reversed or not.
  colourTable = 23
  reverseCT = 0

  ;; See if the user has Coyote's Brewer colour table file and
  ;; see if the user has write-access to it
  brewerFile = Find_Resource_File('fsc_brewer.tbl')

  ;; If the fsc_brewer.tbl file was found then brewerFile
  ;; will contain a string with the full path to the file.
  IF brewerFile THEN BEGIN
    ;; Find out how many colour tables there
    ;; are in the brewerFile
    LOADCT, FILE=brewerFile, GET_NAMES=names
    numOfCT = N_ELEMENTS(names)
  ENDIF ELSE BEGIN ;; fsc_brewer.tbl wasn't found, brewerFile contains an empty string
    ;; Find out how many colour tables there are in
    ;; the default IDL colour table
    LOADCT, GET_NAMES=names
    numOfCT = N_ELEMENTS(names)
  ENDELSE

  info = { rMin       : rMin,       $
           rMax       : rMax,       $
           iMin       : iMin,       $
           iMax       : iMax,       $
           zoom       : 2.0,        $
           numIter    : numIter,    $
           extraIter  : 50,         $
           imageSize  : imageSize,  $
           theFractal : PTR_NEW(),  $
           colourTable: colourTable,$
           reverseCT  : reverseCT,  $
           brewerFile : brewerFile, $
           numOfCT    : numOfCT,    $
           oDrawRef   : PTR_NEW(),  $
           oImageRef  : PTR_NEW(),  $
           oViewRef   : PTR_NEW(),  $
           oPaletteRef: PTR_NEW(),  $
           viewIter   : 1 }

  WIDGET_CONTROL, /REALIZE, tlb

  WIDGET_CONTROL, drawWidget, GET_VALUE=oDrawRef

  WIDGET_CONTROL, tlb, SET_UVALUE=info, /NO_COPY

  XMANAGER, 'tlb', tlb, /NO_BLOCK


  ;; Calculate and display the initial fractal
  WIDGET_CONTROL, tlb, GET_UVALUE=info, /NO_COPY

  oView    = OBJ_NEW('IDLgrView', VIEWPLANE_RECT=[0, 0, info.imageSize[0], info.imageSize[1]])
  oModel   = OBJ_NEW('IDLgrModel')
  oPalette = OBJ_NEW('IDLgrPalette')

  IF info.brewerfile THEN BEGIN
    ;; Load the Brewer colour table into the oPalette
    oPalette -> LoadCT, info.colourTable, FILE=info.brewerFile
  ENDIF ELSE BEGIN
    ;; Load the default IDL colour table into the oPalette
    oPalette -> LoadCT, info.colourTable
  ENDELSE

  oImage = OBJ_NEW('IDLgrImage', PALETTE=oPalette)

  oModel -> Add, oImage
  oView  -> Add, oModel

  theFractal = OBJ_NEW('DJP_Mandelbrot', imageSize=imageSize)

  info.oImageRef   = PTR_NEW(oImage)
  info.oDrawRef    = PTR_NEW(oDrawRef)
  info.oViewRef    = PTR_NEW(oView)
  info.oPaletteRef = PTR_NEW(oPalette)
  info.theFractal  = PTR_NEW(theFractal)

  IF info.viewIter EQ 1 THEN BEGIN
    FOR i=0, info.numIter-1 DO BEGIN
      *info.theFractal -> Iterate
      *info.theFractal -> Draw, oImageRef=info.oImageRef, oWindowRef=info.oDrawRef, oViewRef=info.oViewRef
    ENDFOR
  ENDIF ELSE BEGIN
    *info.theFractal -> Iterate, info.numIter
    *info.theFractal -> Draw, oImageRef=info.oImageRef, oWindowRef=info.oDrawRef, oViewRef=info.oViewRef
  ENDELSE

  ;; Send the info structure back to the tlb.
  WIDGET_CONTROL, tlb, SET_UVALUE=info, /NO_COPY

END


PRO fractal, GROUP_LEADER=wGroup, _EXTRA=_VWBExtra_
  tlb, GROUP_LEADER=wGroup, _EXTRA=_VWBExtra_
END
